﻿using Abp.Domain.Entities;
using Abp.EntityFrameworkCore;
using Abp.EntityFrameworkCore.Repositories;
using Basefr.Core.Contracts;
using Basefr.Core.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Basefr.Data.EntityFrameworkCore
{
    /// <summary>
    /// Repository基类
    /// </summary>
    public abstract class Repository<TDbContext, TEntity, TPrimaryKey> : EfCoreRepositoryBase<TDbContext, TEntity, TPrimaryKey>, IRepository<TEntity, TPrimaryKey>
        where TDbContext : DbContext<TDbContext>
        where TEntity : Entity<TPrimaryKey>
        where TPrimaryKey : struct
    {
        protected Repository(IDbContextProvider<TDbContext> dbContextProvider) : base(dbContextProvider)
        {

        }

        public override TEntity Get(TPrimaryKey id)
        {
            var entity = base.Get(id);

            if (entity == null)
            {
                throw new EntityNotFoundException(typeof(TEntity), id);
            }

            return entity;
        }

        public virtual void Delete(IEnumerable<TEntity> entities)
        {
            var items = entities?.ToArray() ?? new TEntity[0];

            for (var i = items.Length - 1; i >= 0; i--)
            {
                Delete(items[i]);
            }
        }
    }

    /// <summary>
    /// Repository基类
    /// </summary>
    public abstract class Repository<TDbContext, TEntity> : Repository<TDbContext, TEntity, int>
        where TDbContext : DbContext<TDbContext>
        where TEntity : Entity
    {
        protected Repository(IDbContextProvider<TDbContext> dbContextProvider) : base(dbContextProvider)
        {

        }
    }

    /// <summary>
    /// 不限定泛型类型的Repository基类
    /// </summary>
    public abstract class Repository : IRepository
    {
        public abstract IRepository<TEntity, int> GetRepository<TEntity>() where TEntity : EntityBase<int>;

        public virtual int Count<TEntity>() where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().Count();

        public virtual int Count<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().Count(predicate);

        public virtual void Delete<TEntity>(int id) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().Delete(id);

        public virtual void Delete<TEntity>(TEntity entity) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().Delete(entity);

        public virtual void Delete<TEntity>(IEnumerable<TEntity> entities) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().Delete(entities);

        public virtual void Delete<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().Delete(predicate);

        public virtual TEntity FirstOrDefault<TEntity>(int id) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().FirstOrDefault(id);

        public virtual TEntity FirstOrDefault<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().FirstOrDefault(predicate);

        public virtual TEntity Single<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().Single(predicate);

        public virtual TEntity Get<TEntity>(int id) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().Get(id);

        public virtual IQueryable<TEntity> GetAll<TEntity>() where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().GetAll();

        public virtual IQueryable<TEntity> GetAllIncluding<TEntity>(params Expression<Func<TEntity, object>>[] propSelectors) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().GetAllIncluding(propSelectors);

        public virtual List<TEntity> GetAllList<TEntity>() where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().GetAllList();

        public virtual List<TEntity> GetAllList<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().GetAllList(predicate);

        public virtual TEntity Insert<TEntity>(TEntity entity) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().Insert(entity);

        public virtual int InsertAndGetId<TEntity>(TEntity entity) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().InsertAndGetId(entity);

        public virtual TEntity Update<TEntity>(TEntity entity) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().Update(entity);

        public virtual TEntity Update<TEntity>(int id, Action<TEntity> action) where TEntity : EntityBase<int> =>
            GetRepository<TEntity>().Update(id, action);
    }
}
